<?php

defined('IN_CART') or die;

/**
 *
 * session管理类
 * 
 */
class Session {
	
	private $lifetime		= 1800;//30分钟，session有效期

	private $session_name	= '';//sesson名

	private $session_id		= '';//sessonid

	private $session_time	= '';

	private $session_md5	= '';//session md5值，检查session是否改变

	private static $instance;

	/**
     * 构造函数
     * @access private
     * @param  string $session_name session名称
	 * @param  string $session_id   sessionid
	 * @param  int    $lifetime	    session有效期
     */
	private function __construct($session_name = 'sess',$session_id = '',$lifetime = 1800) {

		$GLOBALS['_session']	= array();
		
		$this->session_name		= $session_name;
		$this->lifetime			= $lifetime;
		

		//验证session_id
		$tmpsess_id = $session_id ? $session_id : cgetcookie($session_name);
		$session_id = substr($tmpsess_id,0,32);
		$verify		= substr($tmpsess_id,32);

		if($session_id && $this->gene_salt($session_id) == $verify) {
			$this->session_id = $session_id;
		}
		
		//关闭时执行gc
		register_shutdown_function(array(&$this, 'gc'));
	}
	
	/**
     * 获取一个session实例
     * @access public
     * @param  string $session_name session名称
	 * @param  string $session_id   sessionid
	 * @param  int    $lifetime	    session有效期
     */
	public static function getInstance($session_name = 'sess',$session_id = '',$lifetime = 1800) {
		if(!self::$instance) {
			self::$instance = new Session($session_name,$session_id,$lifetime);
		}
		return self::$instance;
	}
	
	/**
     * 构造函数
     * @access public
     */
	public function init() {
		if($this->session_id) {//session_id 存在，加载session
			$this->read();
		} else {			  //session_id 不存在,生成，写入到cookie
			$this->session_id = $this->gene_session_id();
			$this->add();
			csetcookie($this->session_name,$this->session_id.$this->gene_salt($this->session_id));
		}
	}

	/**
	 *
	 * 添加一个session
	 *
	 */
	private function add() {
		D("session")->data(array("session_id"	=>$this->session_id,
								 "session_data"	=>'a:0:{}',
								 "time"			=>C_TIME))
					->add();
	}
	
	/**
	 *
	 * 生成session_id
	 *
	 */
	private function gene_session_id() {
		$id = strval(C_TIME);
		while(strlen($id) < 32) {
			$id .= mt_rand();
		}
		return md5(uniqid($id,true));
	}
	
	/**
	 *
	 * 生成salt,验证
	 *
	 */
	private function gene_salt($session_id) {
		$ip = getClientIp();
		return sprintf("%8u",crc32(CPATH_ROOT.(isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:"").$ip.$session_id));
	}
	
	/**
	 *
	 * 读出session
	 *
	 */
	private function read() {
		$session = D("session")->where("session_id = '".$this->session_id."'")
							   ->selectrow();
		
		if($session && $session['time']  > C_TIME - $this->lifetime) {//session有效
			$this->session_md5		= md5($session['session_data']);
			$this->session_time		= $session['time'];
			$GLOBALS['_SESSION']    = @unserialize($session['session_data']);
		} else {		//session无效
			if(!$session) {//session不存在
				$this->add();	
			}
			$this->session_md5		= md5('a:0:{}');
			$this->session_time		= 0;
			$GLOBALS['_SESSION']	= array();
		}
	}
	
	/**
	 *
	 * 更新session
	 *
	 */
	private function write() {
		$session	 = serialize(!empty($GLOBALS['_SESSION'])?$GLOBALS['_SESSION']:array());
		
		//session未变化，两次请求时间小于10s
		if(md5($session) == $this->session_md5 && C_TIME - $this->session_time < 10 ) {
			return true;
		}
		
		$data = array("time"		=>C_TIME,"session_data"=>$session);
		$ret  = D("session")->data($data)
							->where($this->session_id)
						    ->limit(1)
							->update();
		return $ret;
	}
	
	/**
	 *
	 * 删除过期session
	 *
	 */
	public function gc() {
		$this->write();
		if(C_TIME % 2 == 0) {
			D("session")->delete("time < ".(C_TIME - $this->lifetime));
		}
		return true;
	}

}
